﻿using System.Globalization;
using System.Net.NetworkInformation;
using System.Reflection;
using System.Text;
using Newtonsoft.Json;

namespace Devonline.Core;

public static class StringExtensions
{
    /// <summary>
    /// 获取类型 TValue 的转换值, 或者默认值
    /// </summary>
    /// <returns></returns>
    public static TValue? GetValueOrDefault<TValue>(this string value) where TValue : IConvertible => string.IsNullOrWhiteSpace(value) ? default : value.To<TValue>();
    /// <summary>
    /// json 字符串转对象, 泛型用法
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value"></param>
    /// <returns></returns>
    public static T? ToJsonObject<T>(this string value) => JsonConvert.DeserializeObject<T>(value, AppSettings.JsonSerializerSettings);
    /// <summary>
    /// json 字符串转对象, 非泛型用法
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="value"></param>
    /// <returns></returns>
    public static object? ToJsonObject(this string value, Type type) => JsonConvert.DeserializeObject(value, type, AppSettings.JsonSerializerSettings);

    /// <summary>
    /// 字符串是否为空或 null
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static bool IsNullOrEmpty(this string value) => string.IsNullOrEmpty(value);
    /// <summary>
    /// 字符串是否不为空或 null
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    public static bool IsNotNullOrEmpty(this string value) => !string.IsNullOrEmpty(value);
    /// <summary>
    /// 判断字符串是否无值, 既不为空也不为空格
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static bool IsNullOrWhiteSpace(this string value) => string.IsNullOrWhiteSpace(value);
    /// <summary>
    /// 判断字符串是否有值, 既不为空也不为空格
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static bool IsNotNullOrWhiteSpace(this string value) => !string.IsNullOrWhiteSpace(value);

    /// <summary>
    /// 获取文件的绝对路径
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    public static string GetAbsolutePath(this string path) => Path.GetPathRoot(path) == null ? path : Path.Combine(AppSettings.StartupPath, path);

    /// <summary>
    /// 对字符串值按 THashAlgorithm 算法计算 Hash Code
    /// </summary>
    /// <typeparam name="THashAlgorithm">Hash 算法</typeparam>
    /// <param name="hashAlgorithm">hash 算法实例</param>
    /// <param name="value">待计算值</param>
    /// <param name="encoding">编码方式</param>
    /// <returns></returns>
    public static string GetHashCode<THashAlgorithm>(this THashAlgorithm hashAlgorithm, string value, Encoding? encoding = null) where THashAlgorithm : System.Security.Cryptography.HashAlgorithm => Convert.ToBase64String(hashAlgorithm.ComputeHash((encoding ?? Encoding.UTF8).GetBytes(value)));
    /// <summary>
    /// 对字符串值按 THashAlgorithm 算法计算 Hash Code
    /// </summary>
    /// <typeparam name="THashAlgorithm">Hash 算法</typeparam>
    /// <param name="value">待计算值</param>
    /// <param name="encoding">编码方式</param>
    /// <returns></returns>
    public static string GetHashValue<THashAlgorithm>(this string value, Encoding? encoding = null) where THashAlgorithm : System.Security.Cryptography.HashAlgorithm
    {
        var type = typeof(THashAlgorithm);
        using var hashAlgorithm = type.InvokeMember(nameof(System.Security.Cryptography.HashAlgorithm.Create), BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, null, CultureInfo.CurrentCulture) as THashAlgorithm;
        if (hashAlgorithm == null)
        {
            throw new Exception($"type Hash Algorithm of {type} can't be created!");
        }

        return Convert.ToBase64String(hashAlgorithm.ComputeHash((encoding ?? Encoding.UTF8).GetBytes(value)));
    }

    /// <summary>
    /// 首字母转小写
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static string FirstCharToLower(this string value)
    {
        if (value.IsNotNullOrEmpty() && char.IsUpper(value[AppSettings.UNIT_ZERO]))
        {
            return char.ToLower(value[AppSettings.UNIT_ZERO], CultureInfo.CurrentCulture) + value[1..];
        }

        return value;
    }
    /// <summary>
    /// 首字母转大写
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static string FirstCharToUpper(this string value)
    {
        if (value.IsNotNullOrEmpty() && char.IsLower(value[AppSettings.UNIT_ZERO]))
        {
            return char.ToUpper(value[AppSettings.UNIT_ZERO], CultureInfo.CurrentCulture) + value[1..];
        }

        return value;
    }

    /// <summary>
    /// ping a host and then execute the action
    /// </summary>
    /// <param name="host"></param>
    /// <param name="success"></param>
    /// <param name="fail"></param>
    /// <returns></returns>
    public static async Task PingStateAsync(this string host, Action? success, Action? fail)
    {
        var ping = new Ping();
        var pingReply = await ping.SendPingAsync(host, AppSettings.UNIT_TEN * AppSettings.UNIT_THOUSAND);
        if (pingReply.Status == IPStatus.Success)
        {
            success?.Invoke();
        }
        else
        {
            fail?.Invoke();
        }
    }
}